package eliauk.fun.flowabledemo.controller;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import eliauk.fun.flowabledemo.FlowableConstant;
import eliauk.fun.flowabledemo.dto.ApproveDto;
import eliauk.fun.flowabledemo.dto.TaskPageQuery;
import eliauk.fun.flowabledemo.service.FlowService;
import eliauk.fun.flowabledemo.service.MyTaskService;
import eliauk.fun.flowabledemo.vo.CommentVo;
import eliauk.fun.flowabledemo.vo.Page;
import eliauk.fun.flowabledemo.vo.Person;
import eliauk.fun.flowabledemo.vo.TaskVo;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.common.engine.impl.identity.Authentication;
import org.flowable.engine.*;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.engine.task.Comment;
import org.flowable.image.ProcessDiagramGenerator;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.flowable.task.api.history.HistoricTaskInstanceQuery;
import org.flowable.task.service.impl.persistence.entity.TaskEntityImpl;
import org.flowable.variable.api.history.HistoricVariableInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;

@RestController
public class DemoController {

    @Resource
    private RuntimeService runtimeService;

    @Resource
    private TaskService taskService;

    @Resource
    private RepositoryService repositoryService;

    @Resource
    private HistoryService historyService;

    @Resource
    private ProcessEngine processEngine;


    @Autowired
    private FlowService flowService;

    @Autowired
    private MyTaskService myTaskService;


    /**
     * 部署流程  文件类型 .bpmn20.xml 或者 .bpmn 或者 .bar 或者.zip
     */
    @PostMapping("deploy")
    public String deploy(@RequestParam("name") String name, @RequestParam("file") MultipartFile file) {
        try {
            flowService.deploy(name, file);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "部署成功";
    }


    @GetMapping("start")
    public String startProcess() {
        String processId = "EnterpriseInternalApprove:1:1377504";
        Map<String, Object> variables = new HashMap<>();
        variables.put("assignee", "gege");
        //设置流程发起人
        Authentication.setAuthenticatedUserId("me");
        // processId 流程id  appealId 为这个流程的业务id variables 为流程变量
        runtimeService.startProcessInstanceById(processId, "appealId---0001", variables);
        //这个方法最终使用一个ThreadLocal类型的变量进行存储，也就是与当前的线程绑定，所以流程实例启动完毕之后，需要设置为null，防止多线程的时候出问题。
        Authentication.setAuthenticatedUserId(null);
        return "启动企业内部审核流程成功";
    }

    @PostMapping("/approve")
    public String completeTask(@RequestBody ApproveDto approveDto) {
        // 参数校验
        Assert.notNull(approveDto.getTaskId());
        Task task = taskService.createTaskQuery().taskId(approveDto.getTaskId()).singleResult();
        Assert.notNull(task, "任务不存在或者已经审核完成");


        // 审批添加批注
        taskService.addComment(task.getId(), task.getProcessInstanceId(), "taskResult", approveDto.getResult().toString());
        taskService.addComment(task.getId(), task.getProcessInstanceId(), "taskComment", approveDto.getComment());
        if (approveDto.getResult()) {
            taskService.addComment(task.getId(), task.getProcessInstanceId(), "taskResultMessage", "通过");
        } else {
            taskService.addComment(task.getId(), task.getProcessInstanceId(), "taskResultMessage", "驳回");
        }

        // 审批完成
        HashMap<String, Object> variables = new HashMap<>();
        variables.put(FlowableConstant.CHECK_RESULT, approveDto.getResult());
        taskService.complete(task.getId(), variables);
        return "审批完成";
    }


    @GetMapping("getTask/{taskId}")
    public TaskVo getTask(@PathVariable String taskId) {
        Assert.notNull(taskId, "任务ID不能为空");
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        Assert.notNull(task, "任务不存在");

        // 这里注意不能直接返回Task，Task 是个接口，需要转换为实现类
        TaskEntityImpl taskEntityImpl = (TaskEntityImpl) task;
        Object taskEntity = taskEntityImpl.getPersistentState();

        TaskVo taskVo = new TaskVo();
        taskVo.setTask(taskEntity);

        Person owner = new Person();
        owner.setUserId(1);
        owner.setUserName("张三");
        Person assignee = new Person();
        assignee.setUserId(2);
        assignee.setUserName("李四");
        taskVo.setOwner(owner);
        taskVo.setAssignee(assignee);

        // 任务 审批信息
        List<String> commentTypes = Arrays.asList("taskResult", "taskComment", "taskResultMessage");
        List<CommentVo> commentVos = new ArrayList<>();
        for (String type : commentTypes) {
            List<Comment> comments = taskService.getTaskComments(task.getId(), type);
            for (Comment comment : comments) {
                CommentVo commentVo = new CommentVo(comment);
                commentVos.add(commentVo);
            }
        }
        return taskVo;
    }

    @PostMapping("myTask")
    public Page MyTask(@RequestBody  TaskPageQuery query) {
        String me = query.getMe();
        long totalItemCount = 0L;
        long totalPageCount = 0L;
        List<TaskVo> list = new ArrayList<>();
        switch (query.getTab()) {
            case 1: // 我的发起
                HistoricTaskInstanceQuery historicTaskInstanceQuery = historyService.createHistoricTaskInstanceQuery()
                        .taskOwner(me)
                        .orderByTaskCreateTime().desc();
                // 获取总条数
                totalItemCount = historicTaskInstanceQuery.count();
                // 计算总页数
                totalPageCount = (long) Math.ceil((double) totalItemCount / query.getPageSize());
                // 分页数据
                List<HistoricTaskInstance> historicTaskInstances = historicTaskInstanceQuery.listPage(query.getPageNum() - 1, query.getPageSize());
                list = myTaskService.convertToTaskVos(historicTaskInstances);
                break;
            case 2: // 我的待办 (正在进行的任务在一张表)
                TaskQuery taskQuery = taskService.createTaskQuery()
                        .taskAssignee(me)
                        .orderByTaskCreateTime().desc();
                // 获取总条数
                 totalItemCount = taskQuery.count();
                // 计算总页数
                 totalPageCount = (long) Math.ceil((double) totalItemCount / query.getPageSize());
                // 分页数据
                List<Task> tasks = taskQuery.listPage(query.getPageNum() - 1, query.getPageSize());
                list = myTaskService.convertToTaskVo(tasks);
                break;
            case 3: // 我的已办 (已经完成的任务在一张表)
                HistoricTaskInstanceQuery historicTaskInstanceQuery1 = historyService.createHistoricTaskInstanceQuery()
                        .finished()
                        .taskAssignee(me)
                        .orderByTaskCreateTime().asc();
                // 获取总条数
                 totalItemCount = historicTaskInstanceQuery1.count();
                // 计算总页数
                 totalPageCount = (long) Math.ceil((double) totalItemCount / query.getPageSize());
                // 分页数据
                List<HistoricTaskInstance> historicTaskInstances1 = historicTaskInstanceQuery1.listPage(query.getPageNum() - 1, query.getPageSize());
                list = myTaskService.convertToTaskVos(historicTaskInstances1);
                break;
        }
        return Page.of(list, totalItemCount, totalPageCount);
    }


    @RequestMapping(value = "processDiagram")
    public void createProcessDiagramPic(HttpServletResponse httpServletResponse, String processId) throws Exception {

        ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
        if (pi == null) {
            return;
        }
        Task task = taskService.createTaskQuery().processInstanceId(pi.getId()).singleResult();

        String InstanceId = task.getProcessInstanceId();
        List<Execution> executions = runtimeService
                .createExecutionQuery()
                .processInstanceId(InstanceId)
                .list();

        List<String> activityIds = new ArrayList<>();
        List<String> flows = new ArrayList<>();
        for (Execution exe : executions) {
            List<String> ids = runtimeService.getActiveActivityIds(exe.getId());
            activityIds.addAll(ids);
        }

        /**
         * 生成流程图
         */
        BpmnModel bpmnModel = repositoryService.getBpmnModel(pi.getProcessDefinitionId());
        ProcessEngineConfiguration engconf = processEngine.getProcessEngineConfiguration();
        ProcessDiagramGenerator diagramGenerator = engconf.getProcessDiagramGenerator();
        InputStream in = diagramGenerator.generateDiagram(bpmnModel, "png", activityIds, flows, engconf.getActivityFontName(), engconf.getLabelFontName(), engconf.getAnnotationFontName(), engconf.getClassLoader(), 1.0, true);
        OutputStream out = null;
        byte[] buf = new byte[1024];
        int legth = 0;
        try {
            out = httpServletResponse.getOutputStream();
            while ((legth = in.read(buf)) != -1) {
                out.write(buf, 0, legth);
            }
        } finally {
            if (in != null) {
                in.close();
            }
            if (out != null) {
                out.close();
            }
        }
    }
}
